package de.slothsoft.android.authenticator;

import java.io.IOException;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.Toast;
import de.slothsoft.android.R;

public final class AuthenticationUtil {

    public static final String OPTION_APPLICATION = "application"; //$NON-NLS-1$

    public static final String ACCOUNT_ID = "de.slothsoft.auth"; //$NON-NLS-1$

    public static Bundle options = new Bundle();

    /**
     * Does one of three things: <br>
     * 1. if no account exists, calls a login activity <br>
     * 2. if one account exists, uses this one without showing an activity <br>
     * 3. if more than one account exists, opens a selection dialog
     */

    public static String getLoginToken(Activity context, String authenticationType) {
	try {
	    AccountManager accountManager = AccountManager.get(context);
	    final AccountManagerFuture<Bundle> future = accountManager.getAuthTokenByFeatures(ACCOUNT_ID,
		    authenticationType, null, context, options, null, null, null);
	    return future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
	} catch (OperationCanceledException e) {
	    return null;
	} catch (Exception e) {
	    handleException(context, e, R.string.authenticator_failed);
	    return null;
	}
    }

    /**
     * Add new account to the account manager
     * 
     * @param accountType
     * @param authTokenType
     * @throws IOException
     * @throws AuthenticatorException
     */

    public static Account addNewAccount(final Activity context, final String authenticationType) {
	try {
	    AccountManager accountManager = AccountManager.get(context);
	    AccountManagerFuture<Bundle> future = accountManager.addAccount(ACCOUNT_ID, authenticationType, null,
		    options, context, null, null);
	    Bundle result = future.getResult();
	    return new Account(result.getString(AccountManager.KEY_ACCOUNT_NAME), authenticationType);
	} catch (OperationCanceledException e) {
	    return null;
	} catch (Exception e) {
	    handleException(context, e, R.string.authenticator_failed);
	    return null;
	}
    }

    public static void showAccountPicker(final Activity context, final String authenticationType,
	    final AccountPickerCallBack callBack) {
	AccountManager accountManager = AccountManager.get(context);
	final Account availableAccounts[] = accountManager.getAccountsByType(ACCOUNT_ID);

	final String name[] = new String[availableAccounts.length + 1];
	name[0] = "[Neuer Account]";
	for (int i = 0; i < availableAccounts.length; i++) {
	    name[i + 1] = availableAccounts[i].name;
	}
	context.runOnUiThread(new Runnable() {
	    @Override
	    public void run() {
		AlertDialog alertDialog = new AlertDialog.Builder(context)
			.setTitle("Pick Account")
			.setAdapter(
				new ArrayAdapter<String>(context.getBaseContext(), android.R.layout.simple_list_item_1,
					name), new DialogInterface.OnClickListener() {
				    @Override
				    public void onClick(DialogInterface dialog, int which) {
					Account account = which == 0 ? addNewAccount(context, authenticationType)
						: availableAccounts[which - 1];
					if (callBack != null)
					    if (account != null) {
						callBack.accountPicked(account);
					    } else {
						callBack.noAccountPicked();
					    }
				    }
				}).create();
		alertDialog.show();
	    }
	});
    }

    /**
     * Get the auth token for an existing account on the AccountManager
     * 
     * @param account
     * @param authTokenType
     */

    public static String getExistingAccountAuthToken(final Activity context, Account account,
	    final String authenticationType) {
	AccountManager accountManager = AccountManager.get(context);
	final AccountManagerFuture<Bundle> future = accountManager.getAuthToken(account, authenticationType, null,
		context, null, null);
	return doGetLoginToken(context, future);
    }

    protected static String doGetLoginToken(Activity context, AccountManagerFuture<Bundle> future) {
	try {
	    Bundle bundle = future.getResult();
	    final String authtoken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
	    showMessage(context, context.getString(authtoken != null ? R.string.authenticator_failed
		    : R.string.authenticator_success));
	    return authtoken;
	} catch (Exception e) {
	    handleException(context, e, R.string.authenticator_failed);
	    return null;
	}
    }

    private static void handleException(Activity context, Exception e, int message) {
	showMessage(context, context.getString(message) + e.getMessage());
    }

    private static void showMessage(final Activity context, final String message) {
	context.runOnUiThread(new Runnable() {
	    @Override
	    public void run() {
		Toast.makeText(context.getBaseContext(), message, Toast.LENGTH_SHORT).show();
	    }
	});
    }

    private AuthenticationUtil() {
	// hide me
    }

    /*
     * 
     */

    public static class AccountPickerCallBack {

	public void accountPicked(Account account) {
	    // nothing to do on default
	}

	public void noAccountPicked() {
	    // nothing to do on default
	}
    }
}
